﻿namespace Vibstudio.NetConfigurator.Engine
{
    #region Namespaces

    using System;
    using System.Collections.Generic;

    using Vibstudio.NetConfigurator.Common;
    using Vibstudio.NetConfigurator.Exceptions;
    using Vibstudio.NetConfigurator.Extensions;
    using Vibstudio.NetConfigurator.IoC;
    using Vibstudio.NetConfigurator.Model;

    #endregion

    public class CompositionManager
    {
        #region Fields

        private readonly bool _backup;

        private readonly Dictionary<string, IComposition> _composers;

        private readonly string _rootPath;

        #endregion

        #region Ctor(s)

        private CompositionManager(string rootPath, bool backup)
        {
            _composers = Container.Resolve<IComposition>();

            foreach (KeyValuePair<string, IComposition> composer in _composers)
            {
                composer.Value.Reset();
            }

            _rootPath = rootPath;
            _backup = backup;
        }

        #endregion

        #region Public Methods and Operators

        public static CompositionManager Setup(string rootPath, bool backup)
        {
            return new CompositionManager(rootPath, backup);
        }

        public IEnumerable<ResultConfiguration> Compose()
        {
            var results = new List<ResultConfiguration>();

            IDictionary<Application, List<string>> applicationSettings = ConfigurationHelper.GetApplicationSettings();
            IDictionary<string, List<ConfigurationSetting>> configurationSettings = ConfigurationHelper.GetConfigurationSettings();

            if (_backup)
            {
                ConfigurationHelper.CopyConfigurationsFile();
            }

            foreach (KeyValuePair<Application, List<string>> valuePair in applicationSettings)
            {
                foreach (string value in valuePair.Value)
                {
                    if (configurationSettings.ContainsKey(value))
                    {
                        List<ConfigurationSetting> settings = configurationSettings[value];
                        bool composed = true;
                        string message = string.Empty;

                        try
                        {
                            string composerName = value.Capitalize().Generalize();

                            IComposition composer;
                            _composers.TryGetValue(composerName, out composer);
                            if (composer == null)
                            {
                                throw new UnknownComposerException(composerName);
                            }

                            composed =
                                composer.Compose(
                                    new NetConfig
                                        {
                                            ConfigurationID = value,
                                            ApplicationName = valuePair.Key.ID,
                                            ConfigurationFileReferencePath =
                                                ConfigurationHelper.GetConfigurationFileReferencePath(_rootPath, valuePair.Key),
                                            ConfigurationSettings = settings
                                        });
                        }
                        catch (CompositionPartiallyPerformedException e)
                        {
                            composed = true;
                            message = e.Message;
                        }
                        catch (Exception e)
                        {
                            composed = false;
                            message = e.Message;
                        }
                        finally
                        {
                            results.Add(string.IsNullOrEmpty(message)
                                            ? new ResultConfiguration(valuePair.Key.ID, value, composed)
                                            : new ResultConfiguration(valuePair.Key.ID, value, composed, message));
                        }
                    }
                }
            }

            return results;
        }

        #endregion
    }
}